<template>
  <div class="identification" v-loading="loading">
    <!-- 实名认证卡片 -->
    <el-card>
      <!-- 卡片自定义头部 -->
      <template #header>
        <div class="card-header">
          <span>实名认证</span>
        </div>
      </template>
      <div class="content">
        <!-- 顶部提示 -->
        <div class="top" v-if="userInfo?.authStatus == 1">
          <div class="tips">
            <SvgIcon name="tips" style="margin-right: 5px" />
            <p>
              完成实名认证后才能添加就诊人，正常进行挂号为了不影响后续步骤，建议提前实名认证
            </p>
          </div>
          <el-button type="primary" size="default" @click="changeUserInfo">
            修改信息
          </el-button>
        </div>
        <div class="center">
          <!-- 当前用户已实名认证展示实名认证的信息 -->
          <div v-if="userInfo?.authStatus == 1" class="alreadyName">
            <el-descriptions class="margin-top" :column="1" size="large" border>
              <el-descriptions-item>
                <template #label>
                  <div class="cell-item">用户姓名</div>
                </template>
                {{ userInfo.name }}
              </el-descriptions-item>
              <el-descriptions-item>
                <template #label>
                  <div class="cell-item">证件类型</div>
                </template>
                {{ userInfo.certificatesType == '10' ? '身份证' : '户口本' }}
              </el-descriptions-item>
              <el-descriptions-item>
                <template #label>
                  <div class="cell-item">证件号码</div>
                </template>
                {{ userInfo.certificatesNo }}
              </el-descriptions-item>
            </el-descriptions>
          </div>
          <!-- 当前用户未实名认证展示实名认证表单 -->
          <div v-else class="awaitName">
            <el-form ref="formRef" :model="formData" :rules="rules" status-icon>
              <el-form-item label="用户姓名" prop="name">
                <el-input
                  placeholder="请输入用户真实姓名"
                  v-model="formData.name"
                />
              </el-form-item>
              <el-form-item label="证件类型" prop="certificatesType">
                <el-select
                  placeholder="请选择证件类型"
                  v-model="formData.certificatesType"
                >
                  <el-option
                    v-for="item in certificatesType"
                    :key="item.id"
                    :label="item.name"
                    :value="item.value"
                  />
                </el-select>
              </el-form-item>
              <el-form-item label="证件号码" prop="certificatesNo">
                <el-input
                  placeholder="请输入证件号码"
                  v-model="formData.certificatesNo"
                />
              </el-form-item>
              <!-- 上传证件 -->
              <el-form-item label="上传证件" prop="certificatesUrl">
                <!-- 
                action:上传地址
                list-type:文件列表的类型(设置为picture-card照片墙可以看到已上传的图片)
                multiple:是否支持多选文件
                limit:上传文件最大数量
                v-model:file-list:展示并收集上传图片列表
                before-upload:图片上传前触发的钩子(限制图片类型和大小)
                on-success:图片上传成功触发的钩子(获取服务器返回的图片地址,进行存储)
                on-exceed:图片超出限制触发的钩子(提示错误信息)
                on-preview:点击文件列表中已上传的文件时的钩子(展示图片预览对话框)
                on-remove:文件列表移除文件时的钩子(将已收集到的数据删除,会自动移除fileList中的数据)
                -->
                <el-upload
                  action="http://syt.atguigu.cn/api/oss/file/fileUpload?fileHost=userAuah"
                  :limit="1"
                  v-model:file-list="fileList"
                  list-type="picture-card"
                  :on-preview="onPreview"
                  :before-upload="beforeUpload"
                  :on-success="onSuccess"
                  :on-exceed="onExceed"
                  :on-remove="onRemove"
                >
                  <img
                    src="../../../assets/images/auth_example.png
                  "
                    style="width: 140px"
                  />
                  <!-- 上传文件类型大小提示 -->
                  <template #tip>
                    <div class="el-upload__tip">jpg/png 图片大小不超过 2MB</div>
                  </template>
                </el-upload>
                <!-- 预览对话框 -->
                <el-dialog v-model="dialogVisible">
                  <img
                    :src="dialogImageUrl"
                    style="width: 100%; height: 100%"
                    alt="Preview Image"
                  />
                </el-dialog>
              </el-form-item>
              <!-- 提交/重写 -->
              <el-form-item>
                <div class="bottom">
                  <el-button
                    type="primary"
                    style="margin: 0 70px"
                    @click="submit"
                  >
                    提交
                  </el-button>
                  <el-button type="info" @click="reset">重写</el-button>
                </div>
              </el-form-item>
            </el-form>
          </div>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts" name="Identification">
import { reqCertificatesType, reqUserAuth, reqUserInfo } from '@/api/user'
import type { CertificatesType, UserAuth, UserInfo } from '@/api/user/type'
import {
  ElMessage,
  type UploadFile,
  type UploadFiles,
  type UploadRawFile,
  type UploadUserFile,
} from 'element-plus'
import { onMounted, reactive, ref } from 'vue'

// 控制页面加载
let loading = ref(false)
// 存储当前用户的实名认证信息
let userInfo = ref<UserInfo>()
// 存储证件类型
let certificatesType = ref<CertificatesType[]>()
// 获取表单的ref对象
let formRef = ref()
// 存储表单收集到的数据
let formData = reactive<UserAuth>({
  certificatesNo: '', // 证件号
  certificatesType: '', // 证件类型
  certificatesUrl: '', // 身份证照片URL 需要从fileList中获取
  name: '', // 用户名
})
// 存储上传的照片 每个照片对象类型必须为UploadUserFile类型
const fileList = ref<UploadUserFile[]>([])
// 存储查看大图对话框内的照片URL
const dialogImageUrl = ref('')
// 控制查看大图对话框的显示
const dialogVisible = ref(false)
// 图片上传前执行的钩子回调(限制图片类型和大小)
const beforeUpload = (uploadFile: UploadRawFile) => {
  // 会将要上传文件作为参数传递,返回false则阻止上传
  // 限制图片类型为 jpg/png且大小不超过2MB
  if (
    ['image/jpeg', 'image/png'].includes(uploadFile.type) &&
    uploadFile.size <= 2 * 1024 * 1024
  ) {
    return true
  } else {
    ElMessage.error('上传图片格式不正确或图片大小超过2MB')
    return false
  }
}
// 图片上传成功的钩子回调(获取服务器返回的图片URL)
const onSuccess = (
  response: any,
  _uploadFile: UploadFile,
  _uploadFiles: UploadFiles,
) => {
  // response:服务器返回的数据
  // uploadFile:当前上传的文件对象
  // uploadFiles:所有上传的文件对象
  // 存储服务器返回的图片URL
  formData.certificatesUrl = response.data
  // 对certificatesUrl进行一次表单校验
  formRef.value.validateField('certificatesUrl')
  // formRef.value.clearValidate('certificatesUrl')
}
// 文件列表移除图片的回调
const onRemove = () => {
  // 删除收集到的图片的数据
  formData.certificatesUrl = ''
  ElMessage.success('删除成功')
  // 进行一次表单校验
  formRef.value.validateField('certificatesUrl')
}
// 图片上传超过限制的钩子回调
const onExceed = () => {
  ElMessage.error('上传图片不能超过1张')
}
// 预览图片的回调
const onPreview = (uploadFile: UploadFile) => {
  // 点击文件列表中已上传的文件时的钩子的回调,会注入当前点击图片对象
  // 存储当前点击图片的url
  dialogImageUrl.value = uploadFile.url as string
  // 显示查看大图对话框
  dialogVisible.value = true
}
// 获取当前登录用户实名认证信息的方法
const getUserInfo = async () => {
  // 开启加载
  loading.value = true
  // 获取用户信息
  let result = await reqUserInfo()
  if (result.code === 200) {
    // 存储用户实名认证信息
    userInfo.value = result.data
    // 关闭加载
    loading.value = false
  } else {
    ElMessage.error('获取用户信息失败')
  }
}
// 点击修改用户信息按钮的回调
const changeUserInfo = async () => {
  // 显示实名认证用户信息对话框
  // @ts-ignore
  userInfo.value.authStatus = 0
  // 获取证件类型
  let result = await reqCertificatesType('CertificatesType')
  if (result.code === 200) {
    // 存储证件类型
    certificatesType.value = result.data
  } else {
    ElMessage.error('获取证件类型失败')
  }
}
// 自定义校验规则对姓名进行正则校验
const validatorName = (_rule: any, value: any, callback: any) => {
  // rule:当前字段校验规则对象
  // value:当前校验字段的值
  // callback:校验成功放行函数、校验失败注入错误信息函数
  if (/^(?:[\u4e00-\u9fa5·]{2,16})$/.test(value)) {
    callback() // 正则校验通过
  } else {
    callback(new Error('请输入合法姓名')) // 正则校验不通过返回错误信息
  }
}
// 自定义校验规则：certificatesType值只能为10/20
const validatorType = (_rule: any, value: any, callback: any) => {
  if (['10', '20'].includes(value)) {
    callback()
  } else {
    callback(new Error('请选择正确的证件类型'))
  }
}
// 表单校验规则
const rules = {
  // 用户名：必填，符合中国人姓名格式
  name: [
    { required: true, message: '请输入姓名', trigger: 'blur' },
    { validator: validatorName, trigger: 'blur' },
  ],
  // 证件类型：必填，必须是10或20
  certificatesType: [
    { required: true, message: '请选择证件类型', trigger: 'change' },
    { validator: validatorType, trigger: 'change' },
  ],
  certificatesUrl: [{ required: true, message: '请上传证件' }],
  certificatesNo: [
    { required: true, message: '请输入证件号码', trigger: 'blur' },
    {
      pattern:
        /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/,
      message: '请输入正确的证件号码',
      trigger: 'blur',
    },
  ],
}
// 点击重置按钮的回调
const reset = () => {
  // 清除表单数据
  Object.assign(formData, {
    certificatesNo: '', // 证件号
    certificatesType: '', // 证件类型
    certificatesUrl: '', // 身份证照片URL 需要从fileList中获取
    name: '', // 用户名
  })
  // 清除照片墙的数据
  fileList.value = []
  // 清除表单验证状态
  formRef.value.clearValidate()
}
// 点击提交按钮的回调
const submit = async () => {
  // 表单校验表单
  await formRef.value.validate()
  // 发请求上传用户认证信息
  let result = await reqUserAuth(formData)
  if (result.code === 200) {
    ElMessage.success('实名认证认证成功')
    // 重新获取用户数据,根据用户认证状态判断是否显示认证信息
    getUserInfo()
    // 清除表单数据和表单校验
    reset()
  } else {
    ElMessage.error('实名认证失败')
  }
}
// 组件挂载
onMounted(() => {
  // 发请求获取用户实名认证信息
  getUserInfo()
})
</script>

<style scoped lang="scss">
.card-header {
  color: $base-color;
  font-size: 20px;
}
.content {
  margin: 10px;
  height: 400px;
  .top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: $base-color;
    .tips {
      display: flex;
      justify-content: center;
    }
  }
  .center {
    margin-top: 30px;
    .alreadyName {
      :deep(.el-descriptions) {
        margin-bottom: 20px;
        .el-descriptions__label {
          color: $base-color;
          width: 180px;
          font-weight: bold;
        }
        .el-descriptions__content {
          color: $base-color;
          font-size: 16px;
          padding-left: 30px;
        }
      }
    }
    .awaitName {
      width: 90%;
      margin: 0 auto;
      :deep(.el-form) {
        .el-form-item__label,
        .el-input__inner {
          color: $base-color;
        }
      }
    }
  }
}
</style>
